/*
 * code from http://coding.debuntu.org/c-linux-socket-programming-tcp-simple-http-client
 *
 */

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>


int create_tcp_socket ();
char *get_ip (char *host);
char *build_get_query (char *host, char *page);
void usage ();

#define HOST "coding.debuntu.org"
#define PAGE "/"
#define PORT 80
#define USERAGENT "HTMLGET 1.0"

  struct sockaddr_in *remote;
  int sock;
  int tmpres;
char *ip;
char *get;
static  char *buf=NULL;
int timeout = 0;

static void 
sig_timeout (int signo)
{
	printf ("connect timeout ..\n");
	timeout = 1;
  	close (sock);
}

int
create_tcp_socket ()
{
  int sock;
  if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
      perror ("Can't create TCP socket");
      exit (1);
    }
  return sock;
}


char *
get_ip (char *host)
{
  struct hostent *hent;
  int iplen = 15;
  unsigned char *hip;		//XXX.XXX.XXX.XXX
  char *ip = (char *) malloc (iplen + 1);

  memset (ip, 0, iplen + 1);
  if ((hent = gethostbyname (host)) == NULL)
    {
      herror ("Can't get IP");
      return NULL;
    }
  hip =(unsigned char*)hent->h_addr_list[0];
	
  sprintf(ip,"%u.%u.%u.%u",hip[0],hip[1],hip[2],hip[3]); 

  return ip;
}

char *
build_get_query (char *host, char *page)
{
  char *query;
  char *getpage = page;
  char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n";
  if (getpage[0] == '/')
    {
      getpage = getpage + 1;
      fprintf (stderr, "Removing leading \"/\", converting %s to %s\n", page,
	       getpage);
    }
  // -5 is to consider the %s %s %s in tpl and the ending \0
  query =
    (char *) malloc (strlen (host) + strlen (getpage) + strlen (USERAGENT) +
		     strlen (tpl) - 5);
  sprintf (query, tpl, getpage, host, USERAGENT);

  return query;
}
int
init_http_get (char *host, char *page)
{
  timeout = 0;
  sock = create_tcp_socket ();
  ip = get_ip (host);
  if (ip == NULL)
	return 1;
  fprintf (stderr, "Domain %s IP is %s,page %s\n",host, ip,page);
  remote = (struct sockaddr_in *) malloc (sizeof (struct sockaddr_in *));
  remote->sin_family = AF_INET;
  tmpres = inet_pton (AF_INET, ip, (void *) (&(remote->sin_addr.s_addr)));
  if (tmpres < 0)
    {
      perror ("Can't set remote->sin_addr.s_addr");
      exit (1);
    }
  else if (tmpres == 0)
    {
      fprintf (stderr, "%s is not a valid IP address\n", ip);
      exit (1);
    }
  remote->sin_port = htons (PORT);
  
  //if connect timeout 15 seconds;connect return ;
  signal (SIGALRM,sig_timeout);
  alarm(15);

  if (connect (sock, (struct sockaddr *) remote, sizeof (struct sockaddr)) <
      0)
    {
      perror ("Could not connect");
      return 0;
    }
  alarm(0);
  get = build_get_query (host, page);
  fprintf (stderr, "Query is:\n<<START>>\n%s<<END>>\n", get);

  //Send the query to the server
  int sent = 0;
  while (sent < strlen (get))
    {
      tmpres = send (sock, get + sent, strlen (get) - sent, 0);
      if (tmpres == -1)
	{
	  perror ("Can't send query");
	  exit (1);
	}
      sent += tmpres;
    }

  buf = malloc(BUFSIZ + 1);

  if (buf == NULL)
	{
		printf ("malloc BUFSIZ fail\n");
	}  
  return 0;
}

char * get_web_buf(void)
{
  //now it is time to receive the page
  static int htmlstart = 0;
  static char *htmlcontent;

  memset (buf, 0, sizeof (buf));
  while ((tmpres = recv (sock, buf, BUFSIZ, 0)) > 0)
    {
      if (htmlstart == 0)
	{
	  /* Under certain conditions this will not work.
	   * If the \r\n\r\n part is splitted into two messages
	   * it will fail to detect the beginning of HTML content
	   */
	  htmlcontent = strstr (buf, "\r\n\r\n");
	  if (htmlcontent != NULL)
	    {
	      htmlstart = 1;
	      htmlcontent += 4;
	    }
	}
      else
	{
	  htmlcontent = buf;
	}
      if (htmlstart)
	{
	;//	  fprintf (stdout,"%s\n",htmlcontent);
	}

	return buf;
      //memset (buf, 0, tmpres);
    }
  if (tmpres < 0)
    {
      perror ("Error receiving data");
    }
  free (get);
  free (remote);
  free (ip);
  close (sock);
  free (buf);
  return NULL;
}


